<h2>ActiveForm</h2>
<h3>1、概述</h3>
<p><code>ActiveForm</code>涵盖了绝大多数的表单常用控件，用户可以很方便地编写极少的代码来生成表单。此外，作者对表单的操作写了非常具有扩展性的js代码，因此我们在使用<code>ActiveForm</code>的时候几乎不需要考虑js的编写，当然，如果有特殊操作的话，<code>ActiveForm</code>也支持在特定的位置以事件的方式执行自定义的js代码。</p>
<h3>2、举例</h3>
<p>下面是Login页面的代码，是用<code>ActiveForm</code>实现的：</p>
<pre><code class='language-php' lang='php'>&lt;?php $form = ActiveForm::begin([&#39;id&#39; =&gt; &#39;login-form&#39;]); ?&gt;
    &lt;?= $form-&gt;field($model, &#39;username&#39;)-&gt;textInput([&#39;autofocus&#39; =&gt; true]) ?&gt;
    &lt;?= $form-&gt;field($model, &#39;password&#39;)-&gt;passwordInput() ?&gt;
    &lt;?= $form-&gt;field($model, &#39;rememberMe&#39;)-&gt;checkbox() ?&gt;
    &lt;div class=&quot;form-group&quot;&gt;
    	&lt;?= Html::submitButton(&#39;Login&#39;, [
            &#39;class&#39; =&gt; &#39;btn btn-primary btn-block&#39;,
            &#39;name&#39; =&gt; &#39;login-button&#39;])
        ?&gt;
    &lt;/div&gt;
&lt;?php ActiveForm::end(); ?&gt;
</code></pre>
<p>从例子中我们可以看出<code>ActiveForm</code>有如下优点：</p>
<ul>
    <li>几乎不涉及html/css/js的代码，使开发人员专注于php的开发；</li>
    <li>支持的控件丰富，控件封装度高，易于使用；</li>
    <li>与模型类紧密结合，代码复用率高；</li>

</ul>
<p>但是也有缺点：</p>
<ul>
    <li><p>由于<code>ActiveForm</code>封装度高，不容易读懂代码，使用门槛高；</p>
    </li>
    <li><p><code>$model</code>的使用需要重新渲染页面才能获取，在无刷新页面的需求下开发困难；</p>
    </li>
    <li><p>难懂的代码，对系统交接的要求也较高。</p>
        <p>&nbsp;</p>
    </li>

</ul>
<blockquote><p><strong>目标：坚持学习，熟悉源码，消除缺点，提高源码利用率。</strong></p>
</blockquote>
<p>&nbsp;</p>
<h3>3、工作原理</h3>
<p><code>ActiveForm</code>是在<code>MVC</code>基础上使用的，因此它是由<code>Model</code>类提供数据，<code>controller</code>实现数据传输到<code>view</code>页面，最后完成页面渲染。</p>
<p>开发步骤如下：</p>
<ol>
    <li>创建基于<code>yii\base\Model</code>的模型类；</li>
    <li>模型类中的rules字段有效性规则会被<code>ActiveForm</code>使用，生成js代码；</li>
    <li>在控制器中实例化上述模型类，并返回给view；</li>
    <li>在view中利用从控制器中传过来的模型实例，使用<code>ActiveField</code>布局页面元素;</li>

</ol>
<h4>3.1 模型类</h4>
<p><code>ActiveForm</code>极度依赖Yii的模型类，因此我们需要为它创建合适的模型类作为数据基础，模型类在<code>ActiveForm</code>中的作用如下：</p>
<ul>
    <li><code>ActiveForm</code>需要根据在模型类中定义的属性来创建控件（表单元素）；</li>
    <li><code>ActiveForm</code>需要根据在模型类中定义的<code>rules</code>来自动生成前端数据有效性校验js代码；</li>

</ul>
<p>在我们创建模型类的时候会出现两种情况：</p>
<ol>
    <li><code>ActvieForm</code>要操作的模型对应于数据库中的一张表，此时可以创建继承于<code>ActiveRecord</code>类的模型，如：<code>common\models\User</code>类；</li>
    <li><code>ActvieForm</code>要操作的模型对应于数据库中的多张表或者没有数据表与之对应，此时可以创建继承于<code>yii\base\Model</code>类的模型，如：<code>common\models\LoginForm</code>；</li>

</ol>
<blockquote><p>注意：选择<code>yii\base\Model</code>作为父类使因为<code>ActiveRecord</code>中需要指定tableName。</p>
</blockquote>
<p>代码示例：</p>
<pre><code class='language-php' lang='php'>class LoginForm extends Model
{
    public $username;
    public $password;
    public $rememberMe = true;

    /**
     * {@inheritdoc}
     */
    public function rules()
    {
        return [
            // username and password are both required
            [[&#39;username&#39;, &#39;password&#39;], &#39;required&#39;],
            // rememberMe must be a boolean value
            [&#39;rememberMe&#39;, &#39;boolean&#39;],
            // password is validated by validatePassword()
            [&#39;password&#39;, &#39;validatePassword&#39;],
        ];
    }
}
</code></pre>
<h4>3.2 控制器</h4>
<p>控制器的作用比较直观，就是把模型类的实例作为参数传递到视图，使得<code>ActiveForm</code>可以在生成表单元素和js代码的时候有基础数据。</p>
<p>示例如下：</p>
<pre><code class='language-php' lang='php'>public function actionLogin()
{
    $model = new LoginForm();
    return $this-&gt;render(&#39;login&#39;, [
        &#39;model&#39; =&gt; $model,
    ]);
}
</code></pre>
<h4>3.3 视图</h4>
<p><code>ActiveForm</code>主要是在视图中使用，我们只需要简单的指定模型类的哪些属性需要哪种控件就可以了，<code>ActiveForm</code>会自动完成html代码的创建。</p>
<blockquote><p>注意：<code>ActiveFrom</code>对表单元素的渲染意味着重新加载整个页面，对于对话框中的表单渲染需要通过<code>ajax</code>获取渲染后的表单元素，然后再通过js重写对话框才能实现表单渲染，这个我们以后会详细说明。</p>
</blockquote>
<p>实例如下：</p>
<pre><code class='language-php' lang='php'>&lt;?php $form = ActiveForm::begin([&#39;id&#39; =&gt; &#39;login-form&#39;]); ?&gt;
    &lt;?= $form-&gt;field($model, &#39;username&#39;)-&gt;textInput([&#39;autofocus&#39; =&gt; true]) ?&gt;
    &lt;?= $form-&gt;field($model, &#39;password&#39;)-&gt;passwordInput() ?&gt;
    &lt;?= $form-&gt;field($model, &#39;rememberMe&#39;)-&gt;checkbox() ?&gt;
    &lt;div class=&quot;form-group&quot;&gt;
    	&lt;?= Html::submitButton(&#39;Login&#39;, [
            &#39;class&#39; =&gt; &#39;btn btn-primary btn-block&#39;,
            &#39;name&#39; =&gt; &#39;login-button&#39;])
        ?&gt;
    &lt;/div&gt;
&lt;?php ActiveForm::end(); ?&gt;
</code></pre>
<p>除了html代码，<code>ActiveForm</code>还会创建js代码，这些js代码主要是为了在浏览器中完成客户提交的数据有效性校验，校验规则来自于模型类的rules规则，举例如下：</p>
<pre><code class='language-javascript' lang='javascript'>    jQuery(&#39;#login-form&#39;).yiiActiveForm([{
        &quot;id&quot;: &quot;loginform-username&quot;,
        &quot;name&quot;: &quot;username&quot;,
        &quot;container&quot;: &quot;.field-loginform-username&quot;,
        &quot;input&quot;: &quot;#loginform-username&quot;,
        &quot;error&quot;: &quot;.help-block.help-block-error&quot;,
        &quot;validate&quot;: function(attribute, value, messages, deferred, $form) {
            yii.validation.required(value, messages, {
                &quot;message&quot;: &quot;Username cannot be blank.&quot;
            });
        }
    },
    {
        &quot;id&quot;: &quot;loginform-password&quot;,
        &quot;name&quot;: &quot;password&quot;,
        &quot;container&quot;: &quot;.field-loginform-password&quot;,
        &quot;input&quot;: &quot;#loginform-password&quot;,
        &quot;error&quot;: &quot;.help-block.help-block-error&quot;,
        &quot;validate&quot;: function(attribute, value, messages, deferred, $form) {
            yii.validation.required(value, messages, {
                &quot;message&quot;: &quot;Password cannot be blank.&quot;
            });
        }
    },
    {
        &quot;id&quot;: &quot;loginform-rememberme&quot;,
        &quot;name&quot;: &quot;rememberMe&quot;,
        &quot;container&quot;: &quot;.field-loginform-rememberme&quot;,
        &quot;input&quot;: &quot;#loginform-rememberme&quot;,
        &quot;error&quot;: &quot;.help-block.help-block-error&quot;,
        &quot;validate&quot;: function(attribute, value, messages, deferred, $form) {
            yii.validation.boolean(value, messages, {
                &quot;trueValue&quot;: &quot;1&quot;,
                &quot;falseValue&quot;: &quot;0&quot;,
                &quot;message&quot;: &quot;Remember Me must be either \&quot;1\&quot; or \&quot;0\&quot;.&quot;,
                &quot;skipOnEmpty&quot;: 1
            });
        }
    }], []);
</code></pre>
<h3>4、ActiveField</h3>
<p><code>ActiveForm</code>的<code>field()</code>方法实际返回的是<code>ActiveField</code>对象，也就是说实际生成表单控件html代码的功能是在<code>ActiveField</code>中完成，<code>ActiveField</code>支持的表单控件如下：</p>
<ul>
    <li>input</li>
    <li>textInput</li>
    <li>hiddenInput</li>
    <li>passwordInput</li>
    <li>fileInput</li>
    <li>textarea</li>
    <li>radio</li>
    <li>checkbox</li>
    <li>dropDownList</li>

</ul>
<h4>4.1 input</h4>
<p>定义：</p>
<pre><code class='language-php' lang='php'>$form-&gt;field($model, $attribute)-&gt;input($type, $options)
</code></pre>
<ul>
    <li>$model：从控制器中穿过来的模型对象；</li>
    <li>$attribute：模型中定义过的属性；</li>
    <li>$type：input的类型，如：<code>text</code>, <code>password</code>；</li>
    <li>$options：input中的属性键值对；</li>

</ul>
<p>举例：</p>
<pre><code class='language-php' lang='php'>$form-&gt;field($model, &#39;username&#39;)-&gt;input(&#39;text&#39;, [&#39;autofocus&#39; =&gt; true])
</code></pre>
<p>将会产生如下的html代码：</p>
<pre><code class='language-html' lang='html'>&lt;div class=&quot;form-group field-loginform-username required has-error&quot;&gt;
    &lt;label class=&quot;control-label&quot; for=&quot;loginform-username&quot;&gt;
        Username
    &lt;/label&gt;
    &lt;input type=&quot;text&quot; id=&quot;loginform-username&quot; class=&quot;form-control&quot; name=&quot;LoginForm[username]&quot; autofocus aria-required=&quot;true&quot; aria-invalid=&quot;true&quot; /&gt;
    &lt;p class=&quot;help-block help-block-error&quot;&gt;
        Username cannot be blank.
    &lt;/p&gt;
&lt;/div&gt;
</code></pre>
<p>&nbsp;</p>
